package huanzhao.erp.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import huanzhao.erp.domain.entity.Package;
import huanzhao.erp.domain.entity.*;
import huanzhao.erp.domain.enumerate.error.PermissionError;
import huanzhao.erp.domain.enumerate.error.ProcessError;
import huanzhao.erp.domain.enumerate.error.ValidationError;
import huanzhao.erp.domain.exception.PhoneStateInconsistentException;
import huanzhao.erp.domain.po.Classification;
import huanzhao.erp.domain.po.Result;
import huanzhao.erp.domain.types.*;
import huanzhao.erp.domain.vo.PhoneVO;
import huanzhao.erp.domain.vo.TaskVO;
import huanzhao.erp.mapper.*;
import huanzhao.erp.util.CommonUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author April
 * 2024/6/13 下午6:57
 * @version 1.0
 */
@Service
public class PhoneService extends ServiceImpl<PhoneMapper, Phone> {
    private static final Logger log = LoggerFactory.getLogger(PhoneService.class);
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private final ConcurrentHashMap<Long, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
    private final NotificationService notificationService;
    private final PhoneMapper phoneMapper;
    private final NotificationMapper notificationMapper;
    private final ConvertService convertService;
    private final TaskMapper taskMapper;
    private final BasicService basicService;
    private final TaskService taskService;
    private final CommentMapper commentMapper;
    private final PackageMapper packageMapper;
    private final StaffService staffService;
    private final TeamMapper teamMapper;
    private final PositionService positionService;
    private final MiscService miscService;
    private final StaffMapper staffMapper;
    private final TransferMapper transferMapper;
    private final PhonePublishSoldMapper phonePublishSoldMapper;

    public PhoneService(NotificationService notificationService, PhoneMapper phoneMapper, NotificationMapper notificationMapper, ConvertService convertService, TaskMapper taskMapper, BasicService basicService, @Lazy TaskService taskService, CommentMapper commentMapper, PackageMapper packageMapper, StaffService staffService, TeamMapper teamMapper, PositionService positionService, MiscService miscService1, StaffMapper staffMapper, TransferMapper transferMapper, FinanceSettlementMapper financeSettlementMapper, PhonePublishSoldMapper phonePublishSoldMapper) {
        this.notificationService = notificationService;
        this.phoneMapper = phoneMapper;
        this.notificationMapper = notificationMapper;
        this.convertService = convertService;
        this.taskMapper = taskMapper;
        this.commentMapper = commentMapper;
        this.packageMapper = packageMapper;
        this.basicService = basicService;
        this.taskService = taskService;
        this.staffService = staffService;
        this.teamMapper = teamMapper;
        this.positionService = positionService;
        this.miscService = miscService1;
        // 启动新线程追踪未签收手机
        new Thread(this::trackUnreceivedPhones).start();
        this.staffMapper = staffMapper;
        this.transferMapper = transferMapper;
        this.phonePublishSoldMapper = phonePublishSoldMapper;
    }

    /**
     * 追踪未签收手机
     * 2024/7/23 下午9:38:39
     */
    private void trackUnreceivedPhones() {
        List<Phone> phones = phoneMapper.getUnsignedPhones();
        if (phones == null || phones.isEmpty()) {
            return;
        }
        for (Phone phone : phones) {
            // 计算剩余时间
            long timeLeft = (phone.getCreateTime().getTime() + TimeUnit.DAYS.toMillis(7) - System.currentTimeMillis()) / 1000;
            if (timeLeft <= 0) {
                // 若未发送过超时通知才发送
                if (!notificationMapper.isNotified(phone.getId(), NotificationType.PHONE_TIMEOUT.getValue())) {
                    dealPhoneTimeout(phone);
                }
            } else {
                addScheduledPhone(phone, timeLeft);
            }
        }
    }

    /**
     * 添加未签收手机定时器
     *
     * @param phone    手机信息
     * @param timeLeft 剩余时间，单位：秒
     *                 2024/6/29 下午9:04:58
     */
    private void addScheduledPhone(Phone phone, long timeLeft) {
        ScheduledFuture<?> scheduledTask = scheduler.schedule(() -> {
            dealPhoneTimeout(phone);
            scheduledTasks.remove(phone.getId());
        }, timeLeft, TimeUnit.SECONDS);
        scheduledTasks.put(phone.getId(), scheduledTask);
    }


    /**
     * 按条件查询手机信息
     *
     * @param state         手机状态
     * @param trackingBegin 收货运单号
     * @param IMEI          手机IMEI
     * @param pageNum       页码
     * @param pageSize      每页数量
     * @return IPage<Phone>
     * 2024/6/13 上午11:14:45
     */
    public IPage<PhoneVO> getPhonesByCondition(String state, String trackingBegin, String IMEI, Integer pageNum, Integer pageSize) {
        if (!StringUtils.isEmpty(trackingBegin)) {
            // 添加通配符，方便前缀查询
            trackingBegin = trackingBegin + "%";
        }
        if (!StringUtils.isEmpty(IMEI)) {
            // 添加通配符，方便前缀查询
            IMEI = IMEI + "%";
        }
        IPage<Phone> page = phoneMapper.getPhonesByCondition(state, trackingBegin, IMEI, Page.of(pageNum, pageSize));
        List<PhoneVO> result = new ArrayList<>();
        page.getRecords().forEach(phone -> result.add(convertService.convertPhone(phone)));
        return new Page<PhoneVO>().setRecords(result).setTotal(page.getTotal());
    }

    /**
     * 检查手机信息是否正确
     *
     * @param phone 手机信息
     * @return Result<?>
     * 2024/6/19 下午2:34:39
     */
    public Result<?> checkPhoneInfo(Phone phone) {
        if (phone == null) {
            return Result.error(ValidationError.VALIDATION_ERROR, "手机信息为空");
        }
        // todo: 检查手机信息是否正确
        return Result.ok("手机信息正确");
    }

    /**
     * 添加手机
     *
     * @param phone 手机信息
     *              2024/6/19 下午3:14:00
     */
    public void addPhone(Phone phone) {
//        insertMapper.addPhone(phone);
//        phone.setCreatedTime(new Timestamp(System.currentTimeMillis()));
        addScheduledPhone(phone, TimeUnit.DAYS.toSeconds(7));
    }

    /**
     * 处理手机超时未签收
     *
     * @param phone 手机信息
     *              2024/6/29 下午9:06:41
     */
    private void dealPhoneTimeout(Phone phone) {
        log.warn("7天未签收手机，id：{}，型号：{}，录入时间：{}", phone.getId(), phone.getModel(), phone.getCreateTime());
        // 7天未签收，发送警告消息
        String content = "7天未签收手机，id：" + phone.getId() + "，型号：" + phone.getModel() + "，录入时间：" + phone.getCreateTime();
        // 发送通知
        notificationService.sendNotificationToWarehouse(NotificationType.PHONE_TIMEOUT, content, phone.getId());
    }

    /**
     * 获取手机的流转记录
     *
     * @param phoneId 手机id
     * @return List<Task>
     * 2024/6/18 下午4:51:01
     */
    public List<TaskVO> getPhoneLogs(Long phoneId) {
        List<Task> tasks = taskMapper.getPhoneLogs(phoneId);
        if (tasks == null) {
            return new ArrayList<>();
        }
        List<TaskVO> result = new ArrayList<>();
        tasks.forEach(task -> result.add(convertService.convertTask(task)));
        return result;
    }

    /**
     * 添加录入时失败手机信息
     *
     * @param phone 手机信息
     *              2024/6/19 下午3:18:23
     */
    public void addFailedPhone(Phone phone) {

    }

    /**
     * 库房签收手机
     *
     * @param phoneId 手机信息
     * @param comment 采购员信息
     * @return Result<?>
     * 2024/6/19 下午3:36:17
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<?> signPhone(Long phoneId, String comment) {
        // 1. 将手机状态改为待分货
        updatePhoneState(phoneId, PhoneState.WAIT_DISTRIBUTE, PhoneState.WAIT_SIGN);
        // 2. 添加手机签收备注
        commentMapper.insert(new Comment(phoneId, CommentType.SIGN, comment));
        // 3. 添加手机签收记录
        packageMapper.insert(new Package(false, phoneId, basicService.getCurrentStaffId(), PackageType.PURCHASE_RECEIVE, null, null, null));
        // 4. 取消定时任务
        ScheduledFuture<?> scheduledTask = scheduledTasks.remove(phoneId);
        if (scheduledTask != null) {
            scheduledTask.cancel(false);
        }
        return Result.ok("签收成功");
    }

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<?> signPhone(@NotBlank String imei, String comment) {
        Result<Long> result = checkImeiAndStates(imei, PhoneState.WAIT_SIGN);
        if (result.isError()) {
            return result;
        }
        return signPhone(result.getData(), comment);
    }

    /**
     * 采购员对手机初检
     *
     * @param qc      是否质检
     * @param teamId  渠道id，质检时需要指定
     * @param staffId 员工id：操作为质检时质检员id（根据渠道确定），退货时为库管id（为toC渠道时不指定）
     * @return Result<?>
     * 2024/10/9 21:51:42
     */
    public Result<?> precheckPhone(boolean qc, long taskId, Long teamId, Long staffId, String comment) {
        Task currentTask = taskService.getById(taskId);
        // 检查任务状态
        Long phoneId = currentTask.getPhoneId();

        if (!qc) {
            // 退货的情况
            Staff staff = staffService.getById(staffId);
            // 判读员工是否为仓管
            if (!staff.getWarehouser()) {
                return Result.error(PermissionError.NEED_WAREHOUSER);
            }
            // 分配给仓管退货任务
            taskService.assignTask(phoneId, staffId, TaskType.PURCHASE_RETURN, currentTask);
            // 将状态设置为采购退货中
            updatePhoneState(phoneId, PhoneState.PURCHASE_RETURN, PhoneState.FIRST_CHECKING);
        } else {
            // 质检的情况，必须指定渠道
            if (teamId == null) {
                return Result.error(ValidationError.VALIDATION_ERROR, "未指定渠道");
            }
            Result<?> result = phoneInQcSituation(currentTask, teamId, staffId);
            if (result.isError()) {
                return result;
            }
        }
        // 完成当前任务
        taskService.finishTask(currentTask, comment);
        return Result.ok("操作成功");
    }

    /**
     * 采购员进行初检或二次检查时分配到质检的情况
     *
     * @param currentTask 当前的任务
     * @param teamId      指定的渠道，渠道不为null
     * @param staffId     质检员id，若指定的渠道为toC则不填
     * @return Result<?>
     * 2024/10/9 22:09:57
     */
    private Result<?> phoneInQcSituation(Task currentTask, Long teamId, Long staffId) {
        // 设置但不在数据库更新将当前任务的渠道，以让后续的任务可以继承该渠道
        currentTask.setTeamId(teamId);
        Long phoneId = currentTask.getPhoneId();
        PhoneState[] currentStates = {PhoneState.FIRST_CHECKING, PhoneState.RE_CHECKING, PhoneState.CHECKING_WHEN_TRANSFER, PhoneState.CHECKING_AFTER_RETURN};
        Team team = teamMapper.getTeamById(teamId);
        if (team == null) {
            return Result.error(ProcessError.TEAM_NOT_FOUND, "手机渠道不存在，请更换渠道");
        }
        if (team.getToB()) {
            // 为B端团队，则直接分配给质检员质检任务
            // 判断员工是否为该团队的质检员
            Result<?> result = positionService.checkPosition(staffId, teamId, TeamPositionType.QUALITY_CHECKER);
            if (result.isError()) {
                return result;
            }
            taskService.assignTask(phoneId, staffId, TaskType.QC, currentTask);
            // 将状态设置为质检中
            updatePhoneState(phoneId, PhoneState.QC, currentStates);
        } else {
            // 为C端团队，则分配给团队负责人分配质检员的任务
            Long managerId = team.getManagerId();
            if (managerId == null) {
                return Result.error(ProcessError.TEAM_LEADER_NOT_SET, "未设置团队负责人，请联系业务经理");
            }
            taskService.assignTask(phoneId, managerId, TaskType.DESIGNATE_QC, currentTask);
            // 将状态设置为待指定质检员
            updatePhoneState(phoneId, PhoneState.WAIT_DESIGNATE_QC, currentStates);
        }
        // 设置手机的渠道
        phoneMapper.setPhoneTeamId(phoneId, teamId);
        return Result.ok();
    }

    /**
     * 采购员对手机二次检查
     * 二次检查，不能退货，只能送质检。包含流程图中的维修后初检、转库初检、退货后初检几种任务类型。
     *
     * @param staffId 可选，若手机为toC渠道则不填，否则填质检员id
     * @param teamId  若要更换渠道，则填写该字段
     * @return Result<?>
     * 2024/10/9 21:54:30
     */
    public Result<?> recheckPhone(long taskId, Long staffId, Long teamId, String comment) {
        Task currentTask = taskService.getById(taskId);
        // 检查是否需要更换渠道
        if (teamId == null) {
            // 若不更换渠道，说明使用原渠道，根据业务流程此时一定存在原渠道
            teamId = phoneMapper.getTeamById(currentTask.getPhoneId());
        }
        Result<?> result = phoneInQcSituation(currentTask, teamId, staffId);
        if (result.isError()) {
            return result;
        }
        // 完成当前任务
        taskService.finishTask(currentTask, comment);
        return Result.ok("操作成功");
    }

    /**
     * 批量查询手机信息
     *
     * @param ids 手机id列表
     * @return List<Phone>
     * 2024/7/21 下午6:04:29
     */
    public List<PhoneVO> getPhonesInBatch(List<Long> ids) {
        List<Phone> phones = phoneMapper.getPhonesInBatch(ids);
        List<PhoneVO> result = new ArrayList<>();
        for (int i = 0; i < ids.size(); i++) {
            Long id = ids.get(i);
            if (i >= phones.size()) {
                Phone phone = new Phone();
                phone.setId(id);
                phones.add(phone);
            }
            Phone phone = phones.get(i);
            if (phone == null || !phone.getId().equals(id)) {
                result.add(new PhoneVO());
            } else {
                result.add(convertService.convertPhone(phone));
            }
        }
        return result;
    }

    /**
     * 根据IMEI查询手机信息
     *
     * @param imei IMEI
     * @return List<Phone>
     * 2024/10/9 14:40:33
     */
    public List<Phone> getByImei(@NotBlank String imei) {
        return phoneMapper.getByImei(imei);
    }


    /**
     * 库房分货
     *
     * @param phoneIds    手机id数组
     * @param purchaserId 采购人id
     * @return Result<?>
     * 2024/10/9 17:36:47
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<List<Long>> distributePhones(List<Long> phoneIds, long purchaserId, String comment) {
        List<Long> failedPhones = new ArrayList<>();
        // 对每个手机id进行校验并分货
        for (Long phoneId : phoneIds) {
            Phone phone = getById(phoneId);
            // 正常流程的话是不会出现手机不存在的情况的
            if (phone == null) {
                continue;
            }
            // 检查手机状态是否为待分货
            if (phone.getState() != PhoneState.WAIT_DISTRIBUTE) {
                failedPhones.add(phoneId);
                continue;
            }
            // 添加分货备注
            commentMapper.insert(new Comment(phoneId, CommentType.DISTRIBUTE, comment));
            // 生成待移交状态的分货任务给当前库管
            Task task = taskService.addTransferringTask(phoneId, basicService.getCurrentStaffId(), TaskType.DISTRIBUTE, false);
            // 分配初检任务给采购员
            taskService.assignTask(phoneId, purchaserId, TaskType.FIRST_CHECK, task);
            // 更新手机状态为初检中
            updatePhoneState(phoneId, PhoneState.FIRST_CHECKING, PhoneState.WAIT_DISTRIBUTE);
        }
        return Result.error("分货成功", failedPhones);
    }

    /**
     * 库房进行采购退货
     *
     * @param taskId    任务id
     * @param waybillNo 运单号
     * @return Result<?>
     * 2024/10/10 19:25:59
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<?> returnPhone(long taskId, @NotBlank String waybillNo, String comment) {
        Task currentTask = taskService.getById(taskId);
        Long phoneId = currentTask.getPhoneId();

        BigDecimal price = phoneMapper.getPriceById(phoneId);
        assert price != null;
        // 添加财务记录
        miscService.addFinanceRecord(phoneId, price, FinanceSettlementType.PURCHASE_RETURN, comment);

        // 添加发货记录
        packageMapper.insert(new Package(true, phoneId, basicService.getCurrentStaffId(), PackageType.PURCHASE_RETURN, waybillNo, null, null));

        // 完成任务，手机状态设置为已退货
        taskService.finishTask(currentTask, PhoneState.RETURNED, comment, PhoneState.PURCHASE_RETURN);
        return Result.ok("操作成功");
    }

    /**
     * 根据imei查询处于某状态的手机id列表
     * 该接口用于前端参数传递imei时，可获得处于某状态的手机数量，从而帮助用户更快的获得反馈
     *
     * @param states 手机的状态
     * @return Result<List < Long>>
     * 2024/10/13 10:17:36
     */
    public Result<List<Long>> getPhoneIdsByImeiAndState(@NotBlank String imei, @NotBlank String... states) {
        List<Long> phoneIds = phoneMapper.getIdsByImeiAndStatesWhereExist(imei, states);
        return Result.ok(Objects.requireNonNullElse(phoneIds, Collections.emptyList()));
    }

    /**
     * 录入待销售手机
     *
     * @return Result 返回没有录入成功的imei
     * 2024/10/13 10:22:25
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<Set<String>> enterPhoneForSale(List<String> imeiList, String comment) {
        Classification classification = classifyImeiList(imeiList, PhoneState.STOCKED);
        classification.phoneIdList().forEach(phoneId -> {
            // 添加录入备注
            commentMapper.insert(new Comment(phoneId, CommentType.ENTER_WAIT_SALE, comment));
            // 更新手机状态为待销售
            updatePhoneState(phoneId, PhoneState.WAIT_SALE, PhoneState.STOCKED);
        });
        return Result.ok("录入成功", classification.errorImeiList());
    }

    /**
     * 按照手机状态将imei列表分类
     * 分为正常类：一个imei只对应一台存在于该状态且为报损和丢失的手机
     * 异常类：不为正常类的情况
     *
     * @param imeiList 手机imei列表
     * @param states   手机状态
     * @return Classification
     * 2024/10/13 16:51:52
     */
    private Classification classifyImeiList(List<String> imeiList, PhoneState... states) {
        Classification classification = new Classification();
        for (String imei : imeiList) {
            Result<Long> result = checkImeiAndStates(imei, states);
            if (result.isError()) {
                classification.errorImeiList().add(imei);
            } else {
                classification.phoneIdList().add(result.getData());
            }
        }
        return classification;
    }

    /**
     * 此方法检查在指定状态下一个imei是否存在多台手机
     * 确保该imei在指定状态下只存在有一条手机信息（即使指定了多个状态）
     * 并避免该手机处在不可用状态（损坏或丢失）
     * <p>
     * 用例：checkImeiAndState("imeixxx", PhoneState.WAIT_SALE, PhoneState.OUTBOUND_ONLY, PhoneState.SOLD)
     * 解释：检查imei为imeixxx的手机且状态为待销售或仅出库或已售出存在于系统中且只存在一个
     *
     * @param imei   手机imei
     * @param states 手机状态列表
     * @return Result<?> 有且仅有一个的情况下返回手机id
     * 2024/10/13 14:13:58
     */
    public Result<Long> checkImeiAndStates(String imei, PhoneState... states) {
        String[] stringArray = CommonUtil.toStringArray(states);
        List<Long> phoneIds = phoneMapper.getIdsByImeiAndStatesWhereExist(imei, stringArray);
        String stateList = String.join("、", stringArray);
        if (phoneIds == null || phoneIds.isEmpty()) {
            return Result.error("未找到状态为" + stateList + "的手机");
        }
        if (phoneIds.size() > 1) {
            return Result.error("找到多个相同imei的状态为" + stateList + "的手机，请联系管理员！");
        }
        return Result.ok(phoneIds.get(0));
    }

    /**
     * 仅出库
     *
     * @param imei         手机imei
     * @param warehouserId 执行销售发货的库管id
     * @return Result<?>
     * 2024/10/13 11:27:00
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<?> outboundOnly(@NotBlank String imei, long warehouserId, String comment) {
        Result<Long> result = checkImeiAndStates(imei, PhoneState.WAIT_SALE);
        if (result.isError()) {
            return result;
        }
        return outboundOnly(result.getData(), warehouserId, comment);
    }

    /**
     * 仅出库
     * 对于手机id的重载方法
     *
     * @param warehouserId 执行销售发货的库管id
     * @return Result<?>
     * 2024/10/13 11:27:00
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<Object> outboundOnly(long phoneId, long warehouserId, String comment) {
        commentMapper.insert(new Comment(phoneId, CommentType.OUTBOUND_ONLY, comment));
        // 给自己分配仅出库任务
        Task task = taskService.addTransferringTask(phoneId, basicService.getCurrentStaffId(), TaskType.OUTBOUND_ONLY, false);
        // 给库管分配销售发货任务
        taskService.assignTask(phoneId, warehouserId, TaskType.SHIP_WHEN_SALE, task);
        // 更新手机状态为仅出库
        updatePhoneState(phoneId, PhoneState.OUTBOUND_ONLY, PhoneState.WAIT_SALE);
        return Result.ok("仅出库成功");
    }

    /**
     * 更新手机状态
     * 若当前的状态不为指定的状态其中之一，则抛出异常，以使上层事务回滚
     *
     * @param phoneId       手机id
     * @param newState      要更新到的状态
     * @param currentStates 现在的状态，可以指定多个，满足其中之一即可
     *                      2024/10/13 21:01:00
     */
    public void updatePhoneState(long phoneId, PhoneState newState, PhoneState... currentStates) {
        String[] states = CommonUtil.toStringArray(currentStates);
        boolean success = phoneMapper.updatePhoneState(phoneId, newState.getValue(), states);
        if (!success) {
            String stateList = String.join("或", states);
            log.error("更新手机状态失败：{} -> {}，手机id：{}", stateList, newState.getValue(), phoneId);
            throw new PhoneStateInconsistentException("操作失败，手机状态异常，原状态应为：" + stateList);
        }
    }

    /**
     * 库房进行转库
     *
     * @param purchaserId 员工id：指定的采购员id
     * @param teamId      新的渠道id
     * @return Result<?>
     * 2024/10/11 16:42:13
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<?> transferPhone(@NotBlank String imei, long purchaserId, long teamId, String comment) {
        Result<Long> result = checkImeiAndStates(imei, PhoneState.STOCKED);
        if (result.isError()) {
            return result;
        }
        return transferPhone(result.getData(), purchaserId, teamId, comment);
    }

    /**
     * 库房进行转库
     * 关于手机id 的重载方法
     *
     * @param purchaserId 员工id：指定的采购员id
     * @param teamId      新的渠道id
     * @return Result<?>
     * 2024/10/11 16:42:13
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<?> transferPhone(long phoneId, long purchaserId, long teamId, String comment) {
        Long phoneTeamId = phoneMapper.getTeamById(phoneId);
        // 校验团队
        if (phoneTeamId == teamId) {
            return Result.error("新的渠道不可与当前渠道相同！");
        }
        Team team = teamMapper.selectById(teamId);
        if (team == null) {
            return Result.error("指定的渠道不存在");
        }

        // 校验采购员
        Staff staff = staffMapper.selectById(purchaserId);
        if (!staff.getPurchaser()) {
            return Result.error("指定的员工不为采购员");
        }

        // 添加转库备注
        commentMapper.insert(new Comment(phoneId, CommentType.TRANSFER, comment));

        // 添加转库记录
        transferMapper.insert(new Transfer(phoneId, phoneTeamId, teamId, basicService.getCurrentStaffId(), purchaserId));

        // 改变手机渠道
        phoneMapper.updatePhoneTeam(phoneId, teamId);

        // 给自己分配状态为待接收的转库任务
        Task task = taskService.addTransferringTask(phoneId, basicService.getCurrentStaffId(), TaskType.TRANSFER, false);

        // 分配给采购员转库检查任务
        taskService.assignTask(phoneId, purchaserId, TaskType.CHECK_WHEN_TRANSFER, task);

        // 更新手机状态为转库检查中
        updatePhoneState(phoneId, PhoneState.CHECKING_WHEN_TRANSFER, PhoneState.STOCKED);
        return Result.ok("操作成功");
    }

    /**
     * 录入退货手机
     *
     * @return Result<Set < String>>
     * 2024/10/13 17:01:43
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<Set<String>> enterReturnedPhone(@NotNull @Size(min = 1) List<String> imeiList, String comment) {
        // 只有处于待销售、仅出库、销售收入待结算、已售出可以退货
        PhoneState[] states = {PhoneState.WAIT_SALE, PhoneState.OUTBOUND_ONLY, PhoneState.WAIT_SETTLE_WHEN_SALE, PhoneState.SOLD};
        Classification classification = classifyImeiList(imeiList, states);
        classification.phoneIdList().forEach(phoneId -> {
            // 添加录入备注
            commentMapper.insert(new Comment(phoneId, CommentType.ENTER_RETURN, comment));
            // 若手机状态为销售收入待结算，则尝试撤销财务结算事务
            if (phoneMapper.getStateById(phoneId) == PhoneState.WAIT_SETTLE_WHEN_SALE) {
                miscService.revokeFinanceRecord(phoneId, FinanceSettlementType.SALES_INCOME);
            }
            // 更新手机状态为待退货
            updatePhoneState(phoneId, PhoneState.WAIT_RETURN_WHEN_SALE, states);
        });
        return Result.ok("录入成功", classification.errorImeiList());
    }

    /**
     * 客户退货
     * 该接口目前依据手机的上一个状态进行处理（当前的状态为：销售待退货），当上一个状态为：
     * 待销售、仅出库：触发未发货取回，需要重新入库
     * 销售收入待结算：触发退货签收，需要进行退货检查，并撤回相应的销售结算事务
     * 已售出：触发售后退货签收，需进行退货检查，并生成买家退货结算事务
     *
     * @param staffId 未发货取回是为库管id，其他情况为的采购id
     * @return Result<?>
     * 2024/10/13 19:02:54
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<?> clientReturn(String imei, long staffId, String waybill, String comment) {
        Result<Long> result = checkImeiAndStates(imei, PhoneState.WAIT_RETURN_WHEN_SALE);
        if (result.isError()) {
            return result;
        }
        Long phoneId = result.getData();
        Staff staff = staffMapper.selectById(staffId);
        PhoneState currentState = PhoneState.WAIT_RETURN_WHEN_SALE;
        // 根据手机之前的状态进行处理
        PhoneState lastState = phoneMapper.getLastStateById(phoneId);
        switch (lastState) {
            // 未发货取回的情况
            case WAIT_SALE, OUTBOUND_ONLY: {
                if (!staff.getWarehouser()) {
                    return Result.error("指定的员工不为仓管");
                }
                // 给自己添加状态为待接收的处理退货任务
                Task task = taskService.addTransferringTask(phoneId, basicService.getCurrentStaffId(), TaskType.HANDLE_RETURN, false);
                // 分配给仓管入库任务
                taskService.assignTask(phoneId, staffId, TaskType.STOCK, task);
                // 手机状态设置为待入库
                updatePhoneState(phoneId, PhoneState.WAIT_STOCK, currentState);
                break;
            }
            // 已发货的情况
            case WAIT_SETTLE_WHEN_SALE, SOLD: {
                if (StringUtils.isBlank(waybill)) {
                    return Result.error("未填写运单号");
                }
                if (!staff.getPurchaser()) {
                    return Result.error("指定的员工不为采购员");
                }
                // 发货且财务结算完毕的情况
                if (lastState == PhoneState.SOLD) {
                    // 添加结算记录，价格取最后一次售出的价格
                    miscService.addFinanceRecord(phoneId, phonePublishSoldMapper.getLastSoldPriceById(phoneId), FinanceSettlementType.SALES_RETURN, null);
                }
                // 添加签收记录
                packageMapper.insert(new Package(false, phoneId, basicService.getCurrentStaffId(), PackageType.SALES_RETURN, waybill, null, null));
                // 给自己添加状态为待接收的处理退货任务
                Task task = taskService.addTransferringTask(phoneId, basicService.getCurrentStaffId(), TaskType.HANDLE_RETURN, false);
                // 分配给采购员退货检查任务
                taskService.assignTask(phoneId, staffId, TaskType.CHECK_AFTER_RETURN, task);
                // 更新手机状态为退货检查中
                updatePhoneState(phoneId, PhoneState.CHECKING_AFTER_RETURN, currentState);
                // 更新手机到货类型为销售退货
                phoneMapper.updatePhoneReceiveType(phoneId, PhoneReceiveType.SALES_RETURN);
                break;
            }
            default: {
                throw new PhoneStateInconsistentException("操作失败，手机上一个状态异常");
            }
        }
        // 添加处理退货备注
        commentMapper.insert(new Comment(phoneId, CommentType.HANDLE_RETURN, comment));
        return Result.ok("操作成功");
    }

    /**
     * 录入售后手机
     *
     * @return Result<Set < String>>
     * 2024/10/14 10:07:57
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<Set<String>> enterAftersalePhones(List<String> imeiList, String comment) {
        // 只有处于已售出、售后已发货状态可以售后
        PhoneState[] states = {PhoneState.SOLD, PhoneState.SHIPPED_IN_AS};
        Classification classification = classifyImeiList(imeiList, states);
        classification.phoneIdList().forEach(phoneId -> {
            // 添加录入备注
            commentMapper.insert(new Comment(phoneId, CommentType.ENTER_AFTER_SALE, comment));
            // 更新手机状态为售后待签收
            updatePhoneState(phoneId, PhoneState.WAIT_SIGN_IN_AS, states);
        });
        return Result.ok("录入成功", classification.errorImeiList());
    }

    /**
     * 售后维修签收
     *
     * @param purchaserId 指定的采购员id
     * @return Result<?>
     * 2024/10/14 10:13:48
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Result<?> signAftersalePhone(@NotBlank String imei, long purchaserId, @NotBlank String waybill, String comment) {
        Result<Long> result = checkImeiAndStates(imei, PhoneState.WAIT_SIGN_IN_AS);
        if (result.isError()) {
            return result;
        }
        Long phoneId = result.getData();
        // 添加签收记录
        packageMapper.insert(new Package(false, phoneId, basicService.getCurrentStaffId(), PackageType.AFTER_SALES_RECEIVE, waybill, null, null));
        // 添加签收备注
        commentMapper.insert(new Comment(phoneId, CommentType.AFTER_SALE_SIGN, comment));

        // 给自己分配状态为待接收的维修签收任务
        Task task = taskService.addTransferringTask(phoneId, basicService.getCurrentStaffId(), TaskType.SIGN_FOR_AFTER_SALE, true);
        // 给采购员分配接收售后任务
        taskService.assignTask(phoneId, purchaserId, TaskType.RECEIVE_AFTER_SALE, task);
        // 手机状态设置为待接收售后
        updatePhoneState(phoneId, PhoneState.WAIT_RECEIVE_IN_AS, PhoneState.WAIT_SIGN_IN_AS);
        // 手机到货类型设置为售后维修
        phoneMapper.updatePhoneReceiveType(phoneId, PhoneReceiveType.AFTER_SALE_REPAIR);
        return Result.ok("操作成功");
    }
}
